package com.geovis.emergency.spd.biz.iflytek.thread;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.geovis.emergency.spd.biz.iflytek.config.IflytekConfig;
import com.geovis.emergency.spd.biz.iflytek.model.GraphLink;
import com.geovis.emergency.spd.biz.iflytek.service.IflytekService;
import com.geovis.emergency.spd.biz.pc.service.*;
import com.geovis.emergency.spd.biz.system.service.ISystemFileService;
import com.geovis.emergency.spd.entity.mobile.pojo.vo.DrillPlanTaskMobileDetailVO;
import com.geovis.emergency.spd.entity.pc.entity.*;
import com.geovis.emergency.spd.entity.pc.pojo.enums.CheckStatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.enums.DisasterEventStatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.vo.*;
import com.geovis.emergency.spd.entity.system.constant.SystemFileBusinessConstant;
import com.geovis.emergency.spd.entity.system.entity.SystemFile;
import com.geovis.emergency.spd.entity.system.pojo.dto.SystemFileDTO;
import com.geovis.emergency.spd.entity.system.pojo.dto.SystemFileQueryDTO;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * </p>
 *
 * @author Lonsho
 * @version 1.0
 * @date 2022/8/24
 */
@Component
@RequiredArgsConstructor
public class PushThread {
    private final IflytekService _iflytekService;
    private final IPcPlanService _pcPlanService;
    private final IPcDrillDisasterEventService _pcDrillDisasterEventService;
    private final IPcDrillPlanService _pcDrillPlanService;
    private final IPcDrillPlanDetailService _pcDrillPlanDetailService;
    private final IPcDrillDutyOrgService _pcDrillDutyOrgService;
    private final IPcDrillPlanTaskService _pcDrillPlanTaskService;

    private final ISystemFileService _systemFileService;

    private static IflytekService iflytekService;
    private static IPcPlanService pcPlanService;
    private static IPcDrillDisasterEventService pcDrillDisasterEventService;

    private static IPcDrillPlanService pcDrillPlanService;
    private static IPcDrillPlanDetailService pcDrillPlanDetailService;
    private static IPcDrillDutyOrgService pcDrillDutyOrgService;

    private static IPcDrillPlanTaskService pcDrillPlanTaskService;

    private static ISystemFileService systemFileService;





    @PostConstruct
    public void init() {
        iflytekService = _iflytekService;
        pcPlanService = _pcPlanService;
        pcDrillDisasterEventService = _pcDrillDisasterEventService;
        pcDrillPlanService = _pcDrillPlanService;
        pcDrillPlanDetailService = _pcDrillPlanDetailService;
        systemFileService = _systemFileService;
        pcDrillDutyOrgService = _pcDrillDutyOrgService;
        pcDrillPlanTaskService = _pcDrillPlanTaskService;
    }
    private static ThreadPoolExecutor EXECUTOR_SERVICE = new ThreadPoolExecutor(5, 50, 1L,
            TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024),
            Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    /**
     * 推送演练
     * @param pcDrill
     */
    public static void pushDrill(PcDrill pcDrill){
        execute(() -> {
            IflytekConfig.AUTH_TOKEN();
            String drillPushId = iflytekService.pushDrill(pcDrill);
            ThreadUtil.sleep(1000L);
            //推送演练事件
            pushDrillDisasterEvent(pcDrill.getId(),drillPushId);
            ThreadUtil.sleep(1000L);
            //推送演练关联的预案
            pushPlan(pcDrill.getPcPlanId(),drillPushId);
        });
    }

    /**
     * 推送演练事件
     * @param drillId
     * @param drillPushId
     */
    public static void pushDrillDisasterEvent(String drillId,String drillPushId){
       // execute(()->{
            List<PcDrillDisasterEvent> list = pcDrillDisasterEventService.list(
                    Wrappers.lambdaQuery(PcDrillDisasterEvent.class)
                            .eq(PcDrillDisasterEvent::getPcDrillId, drillId)
                            .and(ew -> ew.eq(PcDrillDisasterEvent::getStatus,
                                            DisasterEventStatusEnum.IN_PROGRESS.getCode()).or()
                                    .eq(PcDrillDisasterEvent::getStatus, DisasterEventStatusEnum.COMPLETED.getCode())
                            )
            );
            List<PcDrillDisasterEventVO> eventList = list.stream().map(pcDrillDisasterEvent -> {
                PcDrillDisasterEventVO pcDrillDisasterEventVO = BeanUtil.toBean(pcDrillDisasterEvent, PcDrillDisasterEventVO.class);
                pcDrillDisasterEventService.setDetailExtra(pcDrillDisasterEventVO, SystemFileBusinessConstant.TYPE_PC_DRILL_DISASTER_EVENT);
                return pcDrillDisasterEventVO;
            }).collect(Collectors.toList());

            List<PcDrillDisasterEventVO> pushList = iflytekService.pushDrillDisasterEvent(eventList);
            if (CollUtil.isNotEmpty(pushList)){
                List<String> idList = pushList.stream().map(PcDrillDisasterEvent::getPushId).collect(Collectors.toList());
                //事件关联演练
                iflytekService.pushLink(drillPushId,idList, IflytekConfig.DRILL_EVENT_LABEL);
                //演练任务
                pushEventTaskPlan(pushList);
            }

       // });
    }

    /**
     * 推送事件任务
     */
    public static void pushEventTaskPlan(List<PcDrillDisasterEventVO> pushEventList){
        //execute(()->{
            List<PcDrillPlan> list = pcDrillPlanService.list(
                    Wrappers.lambdaQuery(PcDrillPlan.class)
                            .in(PcDrillPlan::getPcDrillDisasterEventId, pushEventList.stream().map(PcDrillDisasterEvent::getId).collect(Collectors.toList()))
                            .eq(PcDrillPlan::getStatus, CheckStatusEnum.PASS.getCode())
            );
            List<PcDrillPlanVO2> drillPlanList = Lists.newArrayList();
            for (PcDrillPlan pcDrillPlan : list) {
                SystemFileQueryDTO systemFileQueryDTO = new SystemFileQueryDTO();
                systemFileQueryDTO.setRelatedId(pcDrillPlan.getId());
                systemFileQueryDTO.setType(SystemFileBusinessConstant.TYPE_PC_DRILL_PLAN_TASK);
                List<SystemFileDTO> fileList = systemFileService.getList(systemFileQueryDTO);
                fileList.sort(Comparator.comparing(SystemFileDTO::getCreateTime));

                String groupId = pcDrillPlan.getGroupId();
                String taskDuty = "";
                String dutyOrgName = "";
                if (StrUtil.isNotBlank(groupId)) {
                    taskDuty = pcDrillPlanService.dutyGroup(pcDrillPlan.getPcDrillId(), groupId);
                    PcDrillDutyOrg pcDrillDutyOrg = pcDrillDutyOrgService.getById(groupId);
                    if (ObjectUtil.isNotNull(pcDrillDutyOrg)) {
                        dutyOrgName = pcDrillDutyOrg.getOrgName();
                    }
                }
                List<PcDrillPlanDetail> detailList = pcDrillPlanDetailService.list(
                        Wrappers.lambdaQuery(PcDrillPlanDetail.class)
                                .eq(PcDrillPlanDetail::getPcDrillPlanId, pcDrillPlan.getId())
                );
                String finalTaskDuty = taskDuty;
                String finalDutyOrgName = dutyOrgName;
                List<PcDrillPlanVO2> collect = detailList.stream().map(pcDrillPlanDetail -> {
                    PcDrillPlanVO2 pcDrillPlanVO2 = BeanUtil.toBean(pcDrillPlanDetail, PcDrillPlanVO2.class);
                    pcDrillPlanVO2.setDuty(finalTaskDuty);
                    pcDrillPlanVO2.setDutyOrgName(finalDutyOrgName);
                    return pcDrillPlanVO2;

                }).collect(Collectors.toList());
                drillPlanList.addAll(collect);
            }
            List<PcDrillPlanVO2> pushDrillPlanList =  iflytekService.pushDrillPlan(drillPlanList);
            if (CollUtil.isNotEmpty(pushDrillPlanList)){
                Map<String, List<PcDrillPlanVO2>> listMap = IterUtil.toListMap(pushDrillPlanList, PcDrillPlanVO2::getPcDrillDisasterEventId);
                List<GraphLink> graphLinks = Lists.newArrayList();
                for (Map.Entry<String, List<PcDrillPlanVO2>> entry : listMap.entrySet()) {
                    String eventId = entry.getKey();
                    Optional<PcDrillDisasterEventVO> first = pushEventList.stream().filter(s -> eventId.equals(s.getId())).findFirst();
                    if (first.isPresent()){
                        String pushEventId = first.get().getPushId();
                        List<String> idList = entry.getValue().stream().map(PcDrillPlanVO2::getPushId).collect(Collectors.toList());
                        for (String pushDrillPlanId : idList) {
                            graphLinks.add(new GraphLink(pushEventId, pushDrillPlanId));
                        }
                        //任务和事件关联
//                        iflytekService.pushLink(pushEventId,idList, IflytekConfig.EVENT_TASK_LABEL);
                    }
                }
                //任务和事件关联
                iflytekService.pushLink(graphLinks, IflytekConfig.EVENT_TASK_LABEL);
                //推送演练任务反馈
                pushDrillTaskFeedback(pushDrillPlanList);
            }

       // });
    }

    /**
     * 推送演练任务反馈
     * @param pcDrillPlanList
     */
    public static void pushDrillTaskFeedback(List<PcDrillPlanVO2> pcDrillPlanList){
       // execute(()->{
            List<DrillPlanDetailTaskVO> taskList = Lists.newArrayList();
            for (PcDrillPlanVO2 pcDrillPlan : pcDrillPlanList) {
                DrillPlanTaskMobileDetailVO detail = pcDrillPlanTaskService.detail(pcDrillPlan.getId());
                if (null == detail){
                    continue;
                }
                DrillPlanDetailTaskVO drillPlanDetailTaskVO = BeanUtil.toBean(detail, DrillPlanDetailTaskVO.class);
                drillPlanDetailTaskVO.setPcDrillPlanDetailId(pcDrillPlan.getId());
                drillPlanDetailTaskVO.setTaskContent(pcDrillPlan.getContent());
                drillPlanDetailTaskVO.setContent(detail.getTaskFeedback());
                drillPlanDetailTaskVO.setPrincipalName(pcDrillPlan.getPrincipalName());
                if (ObjectUtil.isNotNull(detail.getFileDTOS())){
                    drillPlanDetailTaskVO.setFileList(detail.getFileDTOS().stream().map(s -> BeanUtil.toBean(s,SystemFile.class)).collect(Collectors.toList()));
                }
                drillPlanDetailTaskVO.setTaskStatistics(detail.getTaskStatistics());
                taskList.add(drillPlanDetailTaskVO);
            }
            ThreadUtil.sleep(1000L);
            List<DrillPlanDetailTaskVO> pushDrillPlanTaskList = iflytekService.pushDrillPlanTask(taskList);
            if (CollUtil.isNotEmpty(pushDrillPlanTaskList)){
                Map<String, List<DrillPlanDetailTaskVO>> listMap = IterUtil.toListMap(pushDrillPlanTaskList, DrillPlanDetailTaskVO::getPcDrillPlanDetailId);
                List<GraphLink> graphLinks = Lists.newArrayList();
                for (Map.Entry<String, List<DrillPlanDetailTaskVO>> entry : listMap.entrySet()) {
                    Optional<PcDrillPlanVO2> first = pcDrillPlanList.stream().filter(s -> s.getId().equals(entry.getKey())).findFirst();
                    if (first.isPresent()){
                        String pushDrillPlanId = first.get().getPushId();
                        List<String> idList = entry.getValue().stream().map(DrillPlanDetailTaskVO::getPushId).collect(Collectors.toList());
                        for (String pushFeedbackId : idList) {
                            graphLinks.add(new GraphLink(pushDrillPlanId,pushFeedbackId));
                        }
                        //任务和事件关联
                       // iflytekService.pushLink(pushId,idList, IflytekConfig.TASK_FEEDBACK_LABEL);
                    }
                }
                //任务和事件关联
                iflytekService.pushLink(graphLinks, IflytekConfig.TASK_FEEDBACK_LABEL);
            }

      //  });
    }
    /**
     * 推送演练关联的预案
     * @param pcPlanId
     * @param drillPushId
     */
    public static void pushPlan(String pcPlanId,String drillPushId){
       // execute(()->{
            if (StrUtil.isNotBlank(pcPlanId)){
                PcPlanDetailVO planDetailVO = pcPlanService.detailVO(pcPlanId);
                String planPushId = iflytekService.pushPlan(planDetailVO);
                if (StrUtil.isNotBlank(planPushId)){
                    ThreadUtil.sleep(1000L);
                    //推送预案成员单位
                    pushPlanDept(planDetailVO.getDutyDeptList(),planPushId);

                    if (StrUtil.isNotBlank(drillPushId)){
                        //演练关联预案
                        iflytekService.pushLink(planPushId, Lists.newArrayList(drillPushId), IflytekConfig.DRILL_PLAN_LABEL);
                    }
                }
            }
      //  });
    }

    /**
     * 推送预案成员单位
     * @param planDutyDeptList
     * @param planPushId
     */
    public static void pushPlanDept(List<PcPlanDutyDeptVO> planDutyDeptList, String planPushId){
      //  execute(()->{
            List<String> idList = iflytekService.pushPlanDeptList(planDutyDeptList);
            //预案关联成员单位
            iflytekService.pushLink(planPushId,idList, IflytekConfig.PLAN_DEPT_LABEL);
      //  });
    }
    /**
     * 推送预案
     * @param planDetailVO
     */
    public static void pushPlan(PcPlanDetailVO planDetailVO){
     //   execute(() -> {
            String id = iflytekService.pushPlan(planDetailVO);
            if (StrUtil.isNotBlank(id)){
                List<String> idList = iflytekService.pushPlanDeptList(planDetailVO.getDutyDeptList());
                iflytekService.pushLink(id,idList, IflytekConfig.PLAN_DEPT_LABEL);
            }
      //  });
    }
    public static void execute(Runnable runnable){
        EXECUTOR_SERVICE.execute(runnable);
    }
}
